﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;


namespace XMLSpriteSheets
{

    public partial class ScrollableImageViewer : UserControl
    {

        #region Member Data and Constants

        private Image pbImage;

        #endregion

        #region Ctor(s)

        public ScrollableImageViewer()
            : this(string.Empty)
        {
        }

        public ScrollableImageViewer(string imageFilePath)
            : this(!string.IsNullOrEmpty(imageFilePath) && File.Exists(imageFilePath) ? Image.FromFile(imageFilePath) : null)
        {
        }

        public ScrollableImageViewer(Image imageObjRef)
        {
            InitializeComponent();

            this.Picture = imageObjRef;
        }

        #endregion

        #region Public/Internal Methods and Properties

        [Browsable(false)]
        public Image Picture
        {
            get
            {
                return pbImage;
            }
            set
            {
                this.pbImage = this.pictureBox.Image = value;
                UpdateScrollBars(true);
            }
        }

        [Browsable(true)]
        public bool ShowFullImage
        {
            get
            {
                return (this.pictureBox.SizeMode == PictureBoxSizeMode.StretchImage);
            }
            set
            {
                this.pictureBox.SizeMode = (value ? PictureBoxSizeMode.StretchImage : PictureBoxSizeMode.Normal);
                UpdateScrollBars(true);
            }
        }

        #endregion

        #region Control Event Handlers

        private void ScrollableImageViewer_Load(object sender, EventArgs e)
        {

        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            UpdateScrollBars(false);
        }

        private void hsBar_Scroll(object sender, ScrollEventArgs e)
        {
            try
            {
                DrawImage(-e.NewValue, -this.vsBar.Value);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void vsBar_Scroll(object sender, ScrollEventArgs e)
        {
            try
            {
                DrawImage(-this.hsBar.Value, -e.NewValue);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        #endregion

        #region Private Helper Methods and Properties

        internal void UpdateScrollBars(bool reset)
        {
            bool imageOK = (this.pbImage != null && this.pictureBox.SizeMode == PictureBoxSizeMode.Normal);
            this.hsBar.Visible = (imageOK && this.pbImage.Width > this.pictureBox.Width);
            this.vsBar.Visible = (imageOK && this.pbImage.Height > this.pictureBox.Height);

            int imgWidth = (this.pbImage == null ? 0 : this.pbImage.Width);
            this.hsBar.Maximum = (imgWidth - this.pictureBox.Width <= 0 ? 0 : imgWidth - this.pictureBox.Width);
            this.hsBar.LargeChange = this.hsBar.Maximum / 10;

            int imgHeight = (this.pbImage == null ? 0 : this.pbImage.Height);
            this.vsBar.Maximum = (imgHeight - this.pictureBox.Height <= 0 ? 0 : imgHeight - this.pictureBox.Height);
            this.vsBar.LargeChange = this.vsBar.Maximum / 10;

            if (this.hsBar.Value < this.hsBar.Minimum || this.hsBar.Value > this.hsBar.Maximum)
            {
                this.hsBar.Value = this.hsBar.Minimum;
            }

            if (this.vsBar.Value < this.vsBar.Minimum || this.vsBar.Value > this.vsBar.Maximum)
            {
                this.vsBar.Value = this.vsBar.Minimum;
            }

            if (reset)
            {
                this.hsBar.Value = this.hsBar.Minimum;
                this.vsBar.Value = this.vsBar.Minimum;
            }
        }

        private void DrawImage(int startX, int startY)
        {
            if (this.pbImage == null)
            {
                return;
            }

            Graphics pbGraphics = this.pictureBox.CreateGraphics();
            BufferedGraphicsContext currentGraphicsContext = BufferedGraphicsManager.Current;

            Rectangle targetRect = new Rectangle(0, 0,
               Math.Min(this.pictureBox.DisplayRectangle.Width, this.pbImage.Width),
               Math.Min(this.pictureBox.DisplayRectangle.Height, this.pbImage.Height));

            using (BufferedGraphics pbGDIBuffer = currentGraphicsContext.Allocate(pbGraphics, targetRect))
            {
                Rectangle drawRect = new Rectangle(startX,
                   startY,
                   this.pbImage.Width,
                   this.pbImage.Height);

                pbGDIBuffer.Graphics.DrawImageUnscaledAndClipped(this.pbImage, drawRect);

                pbGDIBuffer.Render();
            }
        }

        #endregion
    }
}
